package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.exception.LeaseStatusException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.web.admin.mapper.*;
import com.atguigu.lease.web.admin.service.*;
import com.atguigu.lease.web.admin.vo.attr.AttrValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.atguigu.lease.web.admin.vo.room.RoomDetailVo;
import com.atguigu.lease.web.admin.vo.room.RoomItemVo;
import com.atguigu.lease.web.admin.vo.room.RoomQueryVo;
import com.atguigu.lease.web.admin.vo.room.RoomSubmitVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author liubo
 * @description 针对表【room_info(房间信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
public class RoomInfoServiceImpl extends ServiceImpl<RoomInfoMapper, RoomInfo>
        implements RoomInfoService {

    @Autowired
    private RoomLeaseTermService roomLeaseTermService; //房间租约中间表
    @Autowired
    private RoomPaymentTypeService roomPaymentTypeService; //房间支付方式中间表
    @Autowired
    private RoomAttrValueService roomAttrValueService; //房间属性值中间表
    @Autowired
    private RoomLabelService roomLabelService; //房间标签中间表
    @Autowired
    private RoomFacilityService roomFacilityService; //房间配套中间表
    @Autowired
    private GraphInfoService graphInfoService; //房间图片表

    @Autowired
    private LeaseAgreementService leaseAgreementService;

    @Autowired
    private RoomInfoMapper roomInfoMapper;

    @Autowired
    private ApartmentInfoMapper apartmentInfoMapper;
    @Autowired
    private GraphInfoMapper graphInfoMapper;
    @Autowired
    private AttrValueMapper attrValueMapper;
    @Autowired
    private FacilityInfoMapper facilityInfoMapper;
    @Autowired
    private LabelInfoMapper labelInfoMapper;
    @Autowired
    private PaymentTypeMapper paymentTypeMapper;
    @Autowired
    private LeaseTermMapper leaseTermMapper;

    /* // TODO: 2024/12/11 保存或更新房间信息
           实现步骤:
               1. 接收整合数据Vo
               2. 判定是否是修改
               3. 调用room的保存或者更新
               4. 如果是更新,删除中间的四个表数据
               5. 最终一定进行中间表的数据的批量保存*/
    @Override //        1. 接收整合数据Vo
    public void customSaveOrUpdate(RoomSubmitVo roomSubmitVo) {
//        2. 判定是否是修改
        boolean is = roomSubmitVo.getId() != null;
        Long roomId = roomSubmitVo.getId(); //都用到这个 roomSubmitVo.getId() 提出来
//        3. 调用room的保存或者更新
        super.saveOrUpdate(roomSubmitVo);
//        4. 如果是更新,删除中间的四个表数据
        if (is) {
            // 删除租约中间表数据
            LambdaQueryWrapper<RoomLeaseTerm> roomLeaseTermLambdaQueryWrapper = new LambdaQueryWrapper<>();
//            roomLeaseTermLambdaQueryWrapper.eq(RoomLeaseTerm::getRoomId, roomSubmitVo.getId());
            roomLeaseTermLambdaQueryWrapper.eq(RoomLeaseTerm::getRoomId, roomId);
            roomLeaseTermService.remove(roomLeaseTermLambdaQueryWrapper);

            // 删除支付方式中间表数据
            LambdaQueryWrapper<RoomPaymentType> roomPaymentTypeLambdaQueryWrapper = new LambdaQueryWrapper<>();
//            roomPaymentTypeLambdaQueryWrapper.eq(RoomPaymentType::getRoomId, roomSubmitVo.getId());
            roomPaymentTypeLambdaQueryWrapper.eq(RoomPaymentType::getRoomId, roomId);
            roomPaymentTypeService.remove(roomPaymentTypeLambdaQueryWrapper);

            // 删除属性值中间表数据
            LambdaQueryWrapper<RoomAttrValue> roomAttrValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
            roomAttrValueLambdaQueryWrapper.eq(RoomAttrValue::getRoomId, roomId);
            roomAttrValueService.remove(roomAttrValueLambdaQueryWrapper);

            // 删除标签中间表数据
            LambdaQueryWrapper<RoomLabel> roomLabelLambdaQueryWrapper = new LambdaQueryWrapper<>();
            roomLabelLambdaQueryWrapper.eq(RoomLabel::getRoomId, roomId);
            roomLabelService.remove(roomLabelLambdaQueryWrapper);

            // 删除配套中间表数据
            LambdaQueryWrapper<RoomFacility> roomFacilityLambdaQueryWrapper = new LambdaQueryWrapper<>();
            roomFacilityLambdaQueryWrapper.eq(RoomFacility::getRoomId, roomId);
            roomFacilityService.remove(roomFacilityLambdaQueryWrapper);

            // 删除图片表数据
            //因为公寓和房间用的同一个图片表，删除房间的图片，不能把公寓的图片删掉，所以再用ItemType去删选
            LambdaQueryWrapper<GraphInfo> roomGraphInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            roomGraphInfoLambdaQueryWrapper.eq(GraphInfo::getItemId, roomId);
            // 设置图片所属对象类型
            roomGraphInfoLambdaQueryWrapper.eq(GraphInfo::getItemType, ItemType.ROOM);
            graphInfoService.remove(roomGraphInfoLambdaQueryWrapper);
        }
//  todo      5. 最终一定进行中间表的数据的批量保存
        //1. 图片信息
        /* 传过来的是roomSubmitVo，所以要获取到
        从roomSubmitVo对象中提取GraphVo对象的列表，并将其存储在新的变量graphVoList中
        调用了roomSubmitVo对象的getGraphVoList方法。这个方法的返回值是一个List<GraphVo>类型的列表，即graphVoList*/
        // <GraphVo> 现在这个类中只有name和url，再补全数据库表中的item_id，item_type,然后批量保存
        List<GraphVo> graphVoList = roomSubmitVo.getGraphVoList();
        // 判断集合是否为空,不为空的时候才保存
        /*如果graphVoList不为空（即它包含至少一个GraphVo对象），则执行if代码块内的语句。
        这通常用于在执行某些操作之前确保列表中确实有元素，避免在空列表上执行操作导致错误或异常。*/
        if (!CollectionUtils.isEmpty(graphVoList)) {
            //创建了一个新的ArrayList，类型为GraphInfo（ 把GraphVo对象转换为GraphInfo对象），
            // 并将graphVoList的大小作为初始容量传递给ArrayList的构造函数。这样做可以提高性能
            ArrayList<GraphInfo> graphInfoList = new ArrayList<>(graphVoList.size());// graphVoList.size()为了避免扩容或缩容
            // 遍历graphVoList中的每个GraphVo对象，并将其转换为GraphInfo对象，并将其添加到graphInfoList中
            for (GraphVo graphVo : graphVoList) {
                // 把graphVoList中的数据复制到graphInfo中
                //为每个 GraphVo 对象创建一个对应的 GraphInfo 对象
                GraphInfo graphInfo = new GraphInfo();
                //这行代码使用 Apache Commons BeanUtils 库的 copyProperties 方法，将 graphVo 对象的属性复制到 graphInfo 对象中。
                //这个方法会查找两个对象中相同名字的属性，并将 graphVo 对象的属性值复制到 graphInfo 对象的对应属性中。
                BeanUtils.copyProperties(graphVo, graphInfo);
                // 设置图片所属对象id（设置 graphInfo 对象的 itemId 属性为 roomId 的值）
                graphInfo.setItemId(roomId); // == graphInfo.setItemId(roomSubmitVo.getId());
                // 设置图片所属对象类型（设置 graphInfo 对象的 itemType 属性为 ItemType.ROOM 枚举值）
                graphInfo.setItemType(ItemType.ROOM);
                // 将填充好的 GraphInfo 对象添加到 graphInfoList 列表中
                //graphInfoList 是一个 GraphInfo 类型对象的列表，用于存储转换后的 GraphInfo 对象
                graphInfoList.add(graphInfo);
            }
            // 批量保存图片信息
            //在循环结束后，调用 graphInfoService 的 saveBatch 方法，批量保存 graphInfoList 中的所有 GraphInfo 对象。
            graphInfoService.saveBatch(graphInfoList);
        }
        //2. 房间配套
        //新变量类型为Long      Vo的 属性名      存储在新的变量 facilityInfoIds 中
        List<Long> facilityInfoIds = roomSubmitVo.getFacilityInfoIds();
        if (!CollectionUtils.isEmpty(facilityInfoIds)) {  //判断facilityInfoIds 是否为空
            //实体类名(表名)
            List<RoomFacility> roomFacilityList = new ArrayList<>(facilityInfoIds.size());
            for (Long facilityInfoId : facilityInfoIds) { //遍历 facilityInfoIds 集合
                //创建一个 RoomFacility 对象，并将 facilityInfoId 和 roomId 作为参数传递给 builder 方法，然后调用 build 方法创建 RoomFacility 对象
                RoomFacility roomFacility = RoomFacility.builder().facilityId(facilityInfoId).roomId(roomId).build();
                roomFacilityList.add(roomFacility);
            }
            roomFacilityService.saveBatch(roomFacilityList);
        }
        //3. 房间标签
        List<Long> labelInfoIds = roomSubmitVo.getLabelInfoIds();
        if (!CollectionUtils.isEmpty(labelInfoIds)) {
            List<RoomLabel> roomLabelList = new ArrayList<>(labelInfoIds.size());
            for (Long labelInfoId : labelInfoIds) {
                RoomLabel roomLabel = RoomLabel.builder().labelId(labelInfoId).roomId(roomId).build();
                roomLabelList.add(roomLabel);
            }
            roomLabelService.saveBatch(roomLabelList);
        }
        //4. 房间属性
        List<Long> attrValueIds = roomSubmitVo.getAttrValueIds();
        if (!CollectionUtils.isEmpty(attrValueIds)) {
            List<RoomAttrValue> roomAttrValueList = new ArrayList<>(attrValueIds.size());
            for (Long attrValueId : attrValueIds) {
                RoomAttrValue roomAttrValue = RoomAttrValue.builder().attrValueId(attrValueId).roomId(roomId).build();
                roomAttrValueList.add(roomAttrValue);
            }
            roomAttrValueService.saveBatch(roomAttrValueList);
        }
        //5. 支付方式
        List<Long> paymentTypeIds = roomSubmitVo.getPaymentTypeIds();
        if (!CollectionUtils.isEmpty(paymentTypeIds)) {
            List<RoomPaymentType> roomPaymentTypeList = new ArrayList<>(paymentTypeIds.size());
            for (Long paymentTypeId : paymentTypeIds) {
                RoomPaymentType roomPaymentType = RoomPaymentType.builder().paymentTypeId(paymentTypeId).roomId(roomId).build();
                roomPaymentTypeList.add(roomPaymentType);
            }
            roomPaymentTypeService.saveBatch(roomPaymentTypeList);
        }
        //6. 房间租期
        List<Long> leaseTermIds = roomSubmitVo.getLeaseTermIds();
        if (!CollectionUtils.isEmpty(leaseTermIds)) {
            List<RoomLeaseTerm> roomLeaseTermList = new ArrayList<>(leaseTermIds.size());
            for (Long leaseTermId : leaseTermIds) {
                RoomLeaseTerm roomLeaseTerm = RoomLeaseTerm.builder().leaseTermId(leaseTermId).roomId(roomId).build();
                roomLeaseTermList.add(roomLeaseTerm);
            }
            roomLeaseTermService.saveBatch(roomLeaseTermList);
        }
    }

    // TODO: 2024/12/12 条件分页查询 
    @Override
    public void customPage(Page<RoomItemVo> page, RoomQueryVo queryVo) {
        roomInfoMapper.customSelectPage(page, queryVo);
    }

    // TODO: 2024/12/12 根据id获取房间详细信息
    @Override
    public RoomDetailVo queryDetailById(Long id) {
        // 1.根据id查询房间详细信息RoomInfo
        //当前RoomInfoServiceImpl实现类 继承了 ServiceImpl 泛型类，
        // 所以可以直接使用mybatis-puls提供的service层扩展方法
        // 查单个对象 用getById方法
        RoomInfo roomInfo = getById(id);
        // 判断是否为空，如果查不到房间信息返回空，就不用往下走了
        if (roomInfo == null) {
            return null;
        }
        // 2.查询所属公寓信息
        ApartmentInfo apartmentInfo = apartmentInfoMapper.selectById(roomInfo.getApartmentId());
        // 3.根据房间id查询图片集合(vo对象)graphInfoList
        List<GraphVo> graphVoList = graphInfoMapper.queryByItemId(id, ItemType.ROOM);
        // 4.根据房间id查询房间配套集合(vo对象)facilityInfoList
        List<FacilityInfo> facilityInfoList = facilityInfoMapper.queryByRoomId(id);
        // 5.根据房间id查询房间标签集合(vo对象)labelInfoList
        List<LabelInfo> labelInfoList = labelInfoMapper.queryByRoomId(id);
        // 6.根据房间id查询房间属性集合(vo对象)attrValueList
        List<AttrValueVo> attrValueVoList = attrValueMapper.queryByRoomId(id);
        // 7.根据房间id查询支付方式集合(vo对象)paymentTypeList
        List<PaymentType> paymentTypeList = paymentTypeMapper.queryByRoomId(id);
        // 8.根据房间id查询房间租期集合(vo对象)leaseTermList
        List<LeaseTerm> leaseTermList = leaseTermMapper.queryByRoomId(id);
        // 9.将数据合并到RoomDetailVo对象返回即可
        //创建了一个名为roomDetailVo的类的实例，并将其赋值给变量roomDetailVo
        RoomDetailVo roomDetailVo = new RoomDetailVo();
        roomDetailVo.setApartmentInfo(apartmentInfo);
        //调用roomDetailVo对象的setGraphVoList方法，将graphVoList这个列表赋值给roomDetailVo对象的graphVoList属性
        roomDetailVo.setGraphVoList(graphVoList);
        roomDetailVo.setFacilityInfoList(facilityInfoList);
        roomDetailVo.setLabelInfoList(labelInfoList);
        roomDetailVo.setAttrValueVoList(attrValueVoList);
        roomDetailVo.setPaymentTypeList(paymentTypeList);
        roomDetailVo.setLeaseTermList(leaseTermList);
        BeanUtils.copyProperties(roomInfo,roomDetailVo);
        return roomDetailVo;
    }

    // TODO: 2024/12/12 根据id删除房间信息
    @Override
    public void customRemoveById(Long id) {
        //检查是否存在签约状态的房间信息（房间租约状态是2、5、7，是签约的状态不能删除）
        LambdaQueryWrapper<LeaseAgreement> leaseAgreementLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 根据房间id和状态查询签约状态的数据
        leaseAgreementLambdaQueryWrapper.eq(LeaseAgreement::getRoomId, id);
        //状态是签约状态2、5、7
        leaseAgreementLambdaQueryWrapper.in(LeaseAgreement::getStatus, Arrays.asList(2,5,7));
        long count = leaseAgreementService.count(leaseAgreementLambdaQueryWrapper);
        if (count > 0){
            throw new LeaseStatusException(ResultCodeEnum.DELETE_ERROR.getMessage(), ResultCodeEnum.DELETE_ERROR.getCode());
        }

      /*
        * 当前ApartmentInfoServiceImpl实现类 继承了 ServiceImpl 泛型类，
          所以可以直接使用mybatis-puls提供的service层扩展方法
          根据id删除 用removeById方法
        * */
     // 1.根据id删除房间
        removeById(id);
     // 2.删除中间表数据 (图片表：是根据图片id和图片类型 item_type item_id)
    //                 (其它中间表：都是根据传过来的id值，与各个表中的公寓id【getApartmentId】相等就删除)
        //             [删除的是房间对应的中间表，room_facility....]
// 【调用的是mybatis-plus提供的方法，不用考虑逻辑删除问题，用service层方法】
        // 2.1删除房间相关的图片
        LambdaQueryWrapper<GraphInfo> graphInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
//GraphInfo::getItemId是一个方法引用，它指向GraphInfo类中的getItemId方法，id是一个变量，表示特定的公寓ID。
//传过来的id值，等于GraphInfo集合(graph_info表)中item_id列的值，如果item_type是APARTMENT，并且item_id等于传过来的id值，就删除
        graphInfoLambdaQueryWrapper.eq(GraphInfo::getItemId, id);
        graphInfoLambdaQueryWrapper.eq(GraphInfo::getItemType, ItemType.ROOM);
        graphInfoService.remove(graphInfoLambdaQueryWrapper);
        // 2.2删除房间相关的配套
        LambdaQueryWrapper<RoomFacility> roomFacilityInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roomFacilityInfoLambdaQueryWrapper.eq(RoomFacility::getRoomId, id);
        roomFacilityService.remove(roomFacilityInfoLambdaQueryWrapper);
        // 2.3删除房间相关的标签
        LambdaQueryWrapper<RoomLabel> roomLabelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roomLabelLambdaQueryWrapper.eq(RoomLabel::getRoomId, id);
        roomLabelService.remove(roomLabelLambdaQueryWrapper);
        // 2.4删除房间相关的属性
        LambdaQueryWrapper<RoomAttrValue> roomAttrValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roomAttrValueLambdaQueryWrapper.eq(RoomAttrValue::getRoomId, id);
        roomAttrValueService.remove(roomAttrValueLambdaQueryWrapper);
        // 2.5删除房间相关的支付方式
        LambdaQueryWrapper<RoomPaymentType> roomPaymentTypeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roomPaymentTypeLambdaQueryWrapper.eq(RoomPaymentType::getRoomId, id);
        roomPaymentTypeService.remove(roomPaymentTypeLambdaQueryWrapper);
        // 2.6删除房间相关的租期
        LambdaQueryWrapper<RoomLeaseTerm> roomLeaseTermLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roomLeaseTermLambdaQueryWrapper.eq(RoomLeaseTerm::getRoomId, id);
        roomPaymentTypeService.remove(roomPaymentTypeLambdaQueryWrapper);


    }
}




